package io.renren.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.exception.RRException;
import io.renren.common.utils.Constant;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.R;
import io.renren.dao.ApplicationDao;
import io.renren.dao.RoomDao;
import io.renren.entity.ApplicationEntity;
import io.renren.entity.RoomEntity;
import io.renren.entity.RoomEslEntity;
import io.renren.service.ApplicationService;
import io.renren.service.EslContentService;
import io.renren.service.RoomEslService;
import io.renren.vo.ApplicationVo;
import io.renren.vo.HalfHourVo;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


@Service("applicationService")
public class ApplicationServiceImpl extends ServiceImpl<ApplicationDao, ApplicationEntity> implements ApplicationService {
    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationServiceImpl.class);
    @Autowired
    private ApplicationDao applicationDao;

    @Autowired
    private RoomDao roomDao;

    @Autowired
    private RoomEslService roomEslService;
    private EslContentService eslContentService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String subject = null, roomId = null, employeeId = null, employeeName = null, state = null, compId = null;
        String startTime = null, endTime = null;
        List<String> states = new ArrayList<>();
        states.add(Constant.ApplicationState.APPLIED.getValue());
        states.add(Constant.ApplicationState.STARTED.getValue());
        subject = (String) params.get("subject");
        roomId = params.get("roomId") != null ? String.valueOf(params.get("roomId")) : null;
        employeeId = (String) params.get("employeeId");
        employeeName = (String) params.get("employeeName");
        if (params.get("startTime") != null) {
            startTime = DateUtil.format((Date) params.get("startTime"), DatePattern.NORM_DATETIME_FORMAT);
        }
        if (params.get("endTime") != null) {
            endTime = DateUtil.format((Date) params.get("endTime"), DatePattern.NORM_DATETIME_FORMAT);
        }
//        state = Constant.ApplicationState.OVER.getValue(); //只显示非结束状态的会议
        compId = (String) params.get("compId");

        List<ApplicationVo> vos = new ArrayList<>();

        QueryWrapper<ApplicationEntity> queryWrapper = null;
        if (startTime != null && startTime != null) {
            String finalStartTime = startTime;
            String finalEndTime = endTime;
            queryWrapper = new QueryWrapper<ApplicationEntity>()
                    .like(subject != null && StringUtils.isNotBlank(subject), "subject", subject)
                    .eq(roomId != null && StringUtils.isNotBlank(roomId), "room_id", roomId)
                    .eq(employeeId != null && StringUtils.isNotBlank(employeeId), "employee_id", employeeId)
                    .eq(employeeName != null && StringUtils.isNotBlank(employeeName), "employee_name", employeeName)
                    .ne(state != null && StringUtils.isNotBlank(state), "state", state)
                    .in(states != null && states.size() > 0, "state", states)
                    .eq(compId != null && StringUtils.isNotBlank(compId), "comp_id", compId)
                    .and(qw1 -> qw1.lt("start_time", finalStartTime).gt("end_time", finalStartTime)
                            .or(qw3 -> qw3.le("start_time", finalEndTime).ge("end_time", finalEndTime)))
//                    .and(qw -> qw.ge("start_time", startTime).or().le("end_time", endTime))
                    .orderByAsc("start_time");
        } else {
            queryWrapper = new QueryWrapper<ApplicationEntity>()
                    .like(subject != null && StringUtils.isNotBlank(subject), "subject", subject)
                    .eq(roomId != null && StringUtils.isNotBlank(roomId), "room_id", roomId)
                    .eq(employeeId != null && StringUtils.isNotBlank(employeeId), "employee_id", employeeId)
                    .eq(employeeName != null && StringUtils.isNotBlank(employeeName), "employee_name", employeeName)
                    .ne(state != null && StringUtils.isNotBlank(state), "state", state)
                    .in(states != null && states.size() > 0, "state", states)
                    .eq(compId != null && StringUtils.isNotBlank(compId), "comp_id", compId)
                    .orderByAsc("start_time");
        }
        List<ApplicationEntity> applicationEntities = applicationDao.selectList(queryWrapper);

        for (ApplicationEntity applicationEntity : applicationEntities) {
            ApplicationVo vo = ApplicationVo.convertFor(applicationEntity);
            RoomEntity roomEntity = roomDao.selectById(applicationEntity.getRoomId());
            if (roomEntity == null) {
                continue;
            }
            vo.setRoomName(roomEntity.getName());

            Map<String, Object> map = new HashMap<>();
            map.put("roomId", roomEntity.getId());
            map.put("limit", "1000");
            PageUtils roomEslPage = roomEslService.queryPage(map);
            List<RoomEslEntity> roomEslEntities = (List<RoomEslEntity>) roomEslPage.getList();
            List<String> aliases = new ArrayList<>();
            for (RoomEslEntity roomEslEntity : roomEslEntities) {
                if (StringUtils.isNotBlank(roomEslEntity.getAlias())) {
                    aliases.add(roomEslEntity.getAlias());
                }
            }
            vo.setAliases(aliases);

            vos.add(vo);
        }

        return new PageUtils(vos, vos.size(), 10, 1);

    }

    @Override
    public List<ApplicationEntity> queryByRoomId(Long roomId) {

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("roomId", roomId));

        return applications;
    }

    @Override
    public List<ApplicationEntity> queryByRoomIdAndState(Long roomId, String state) {

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("state", state)
                .eq("room_id", roomId));

        return applications;
    }

    @Override
    public List<ApplicationEntity> queryByRoomIdAndStateOrderByIdDescLimit(Long roomId, String state, int limit) {

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("state", state)
                .eq("room_id", roomId)
                .orderByDesc("id")
                .last("limit 1")
        );

        return applications;
    }

    public List<ApplicationEntity> queryNextMeeting(Long roomId, Date startTime) {

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("room_id", roomId)
                .ge("start_time", startTime)
                .in("state", "applied")
                .orderByAsc("start_time")
        );

        return applications;
    }

    @Override
    public List<ApplicationEntity> queryByIds(Set<Long> ids) {
        return applicationDao.selectList(new QueryWrapper<ApplicationEntity>().in("id", ids));
    }

    @Override
    public List<ApplicationEntity> queryByRoomIdAndSubject(Long roomId, String subject) {

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("room_id", roomId)
                .eq("subject", subject)
                .orderByDesc("id")
        );

        return applications;
    }

    @Override
    public Map<String, String> queryBookedTimeByRoomId(Long roomId) {
        List<Map<String, Date>> times = new ArrayList<>();
        HalfHourVo halfHourVo = new HalfHourVo();
        Map<String, String> timeMap = new HashMap<>();

        List<ApplicationEntity> applications = applicationDao.selectList(new QueryWrapper<ApplicationEntity>()
                .eq("room_id", roomId));

        //遍历取会议室的预约时间段
        for (ApplicationEntity application : applications) {
            Map<String, Date> time = new HashMap<>();
            time.put("startTime", application.getStartTime());
            time.put("endTime", application.getEndTime());

            int start = DateUtil.hour(time.get("startTime"), true) * 2;
            if (DateUtil.minute(time.get("startTime")) >= 30) {
                start++;
            }

            int end = DateUtil.hour(time.get("endTime"), true) * 2;
            if (DateUtil.minute(time.get("endTime")) >= 30) {
                end++;
            }
            timeMap = halfHourVo.bookedConvert(timeMap, start, end);


        }
        return timeMap;
    }

    public List<Long> queryBookedRoomIds(String bookDate, String startTime, String endTime) {
        List<Long> roomIds = new ArrayList<>();

        QueryWrapper<ApplicationEntity> queryWrapper = new QueryWrapper<ApplicationEntity>()
                .and(startTime != null && startTime != null, qw -> qw.ge("start_time", startTime).or().le("end_time", endTime));

        List<ApplicationEntity> applicationEntities = applicationDao.selectList(queryWrapper);

        for (ApplicationEntity applicationEntity : applicationEntities) {
            roomIds.add(applicationEntity.getRoomId());
        }

        return roomIds;
    }

    public List<ApplicationEntity> queryUnfinish(Long roomId) {
        List<String> states = new ArrayList<>();
        states.add(Constant.ApplicationState.APPLIED.getValue());
        states.add(Constant.ApplicationState.STARTED.getValue());

        QueryWrapper<ApplicationEntity> queryWrapper = new QueryWrapper<ApplicationEntity>()
                .eq(roomId != null, "room_id", roomId)
                .in("state", states);

        List<ApplicationEntity> applicationEntities = applicationDao.selectList(queryWrapper);

        return applicationEntities;
    }

    @Override
    public boolean save(ApplicationEntity applicationEntity) {
        Map<String, Object> map = new HashMap<>();
        map.put("roomId", applicationEntity.getRoomId());
        map.put("startTime", applicationEntity.getStartTime());
        map.put("endTime", applicationEntity.getEndTime());
        PageUtils pageUtils = queryPage(map);
        if (CollectionUtil.isNotEmpty(pageUtils.getList())) {
            throw new RRException(String.format("预定失败，%s到%s 已有会议", DateUtil.format((Date) map.get("startTime"), DatePattern.NORM_DATETIME_PATTERN), DateUtil.format((Date) map.get("endTime"), DatePattern.NORM_DATETIME_PATTERN)));
        }

        applicationDao.insert(applicationEntity);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R cancel(Set<Long> meetingIds) {
        final List<ApplicationEntity> applicationEntities = this.queryByIds(meetingIds);
        if (CollectionUtil.isEmpty(applicationEntities)) {
            return R.error("没有要取消的会议");
        }

        List<ApplicationEntity> needingRefreshRoom = new ArrayList<>();
        Date now = new Date();

        for (ApplicationEntity applicationEntity : applicationEntities) {

            final Date startTime = applicationEntity.getStartTime();
            final Date endTime = applicationEntity.getEndTime();
            boolean isMeetingNotBegin = startTime.before(now);
            boolean isMeetingFinished = endTime.before(now);

            this.cancelMeeting(applicationEntity.getId());

//            if (!isMeetingFinished && !isMeetingNotBegin) {
            if (!isMeetingFinished) {
                needingRefreshRoom.add(applicationEntity);
            }
        }

        if (CollectionUtil.isNotEmpty(needingRefreshRoom)) {
            for (ApplicationEntity bookedMeeting : needingRefreshRoom) {
                refreshDoorPlate(bookedMeeting);
            }
        }

        return R.ok();
    }

    private void refreshDoorPlate(ApplicationEntity bookedMeeting) {
        final Long roomId = bookedMeeting.getRoomId();

        List<RoomEslEntity> roomEslEntities = roomEslService.queryByRoomIdAndType(roomId, "door");

        if (CollectionUtil.isEmpty(roomEslEntities)) {
            LOGGER.warn("会议室id[{}]没有绑定价签", bookedMeeting.getRoomId());
            return;
        }

        eslContentService.refreshDoorPlate(bookedMeeting, roomEslEntities.get(0));
    }

    private void cancelMeeting(Long id) {
        ApplicationEntity entity = new ApplicationEntity();
        entity.setId(id);
        entity.setState("canceled");

        final boolean updateResult = this.updateById(entity);
        LOGGER.debug("updated application result: {} with id: {}", updateResult, id);
    }

    @Autowired
    public void setEslContentService(EslContentService eslContentService) {
        this.eslContentService = eslContentService;
    }
}
